from PyQt5.QtCore import QObject, Qt, pyqtSignal, QPoint, QRect, QEvent
from PyQt5.QtWidgets import (QMessageBox, QFileDialog, QApplication,
                             QActionGroup, QLabel, QWidget, QPushButton,
                             QLineEdit, QHBoxLayout, QVBoxLayout, QScrollArea,
                             QSplitter, QToolBar, QMenuBar, QMenu, QAction,
                             QTextEdit, QProgressBar)
from PyQt5.QtGui import QKeySequence, QPixmap, QImage, QClipboard, QIntValidator

import fitz
import os

from .controls import ControlId

class InteractionManager(QObject):
    """交互管理器：处理所有控件的信号与槽连接及交互逻辑"""
    
    def __init__(self, control_manager, pdf_doc, main_window, thumbnail_sidebar):
        super().__init__(main_window)
        self.controls = control_manager
        self.pdf_doc = pdf_doc
        self.main_window = main_window
        self.thumbnail_sidebar = thumbnail_sidebar
        
        # 状态变量
        self._save_mode = False  # False: 另存为模式, True: 直接保存模式
        self._zoom = 1.0         # 缩放比例 (1.0 = 100%)
        self._current_page = 0   # 当前页码
        self._total_pages = 0    # 总页数
        
        # 缓存管理
        self._page_cache = {}    # 页面缓存：{页码: QLabel}
        self._thumbnail_cache = {}  # 缩略图缓存
        self._page_positions = {}# 页面位置记录：{页码: 起始Y坐标, "页码_height": 高度}
        
        # 文本选择相关
        self._selecting = False
        self._start_pos = QPoint()
        self._current_rect = QRect()
        self._selected_page = -1
        
        # 初始化动作组（用于单选菜单）
        self.save_mode_group = QActionGroup(self.main_window)
        self.save_mode_group.addAction(self.controls.get(ControlId.ACTION_SAVE_MODE_AS))
        self.save_mode_group.addAction(self.controls.get(ControlId.ACTION_SAVE_MODE_DIRECT))

        # 连接缩略图删除信号
        self.thumbnail_sidebar.delete_page_requested.connect(self._on_delete_page)

        # 安装事件过滤器处理鼠标选择和滚轮缩放
        self.controls.get(ControlId.SCROLL_AREA).viewport().installEventFilter(self)
        self.controls.get(ControlId.PAGES_CONTAINER).installEventFilter(self)
        
        # 连接所有信号与槽
        self._connect_signals()
    
    def _connect_signals(self):
        """连接所有控件的信号与槽函数"""
        # 文件操作
        self.controls.get(ControlId.ACTION_OPEN).triggered.connect(self._on_open_file)
        self.controls.get(ControlId.ACTION_OPEN).setShortcut(QKeySequence("Ctrl+O"))
        self.controls.get(ControlId.ACTION_OPEN).setToolTip("打开PDF文件 (Ctrl+O)")
        
        self.controls.get(ControlId.ACTION_SAVE).triggered.connect(self._on_save_file)
        self.controls.get(ControlId.ACTION_SAVE).setShortcut(QKeySequence("Ctrl+S"))
        self.controls.get(ControlId.ACTION_SAVE).setToolTip("保存PDF文件 (Ctrl+S)")
        
        self.controls.get(ControlId.ACTION_SAVE_AS).triggered.connect(lambda: self._on_save_file(True))
        self.controls.get(ControlId.ACTION_SAVE_AS).setShortcut(QKeySequence("Ctrl+Shift+S"))
        self.controls.get(ControlId.ACTION_SAVE_AS).setToolTip("另存为PDF文件 (Ctrl+Shift+S)")
        
        self.controls.get(ControlId.ACTION_EXPORT_WORD).triggered.connect(self._on_export_word)
        self.controls.get(ControlId.ACTION_EXPORT_WORD).setShortcut(QKeySequence("Ctrl+W"))
        self.controls.get(ControlId.ACTION_EXPORT_WORD).setToolTip("导出为Word (Ctrl+W)")
        
        self.controls.get(ControlId.ACTION_EXIT).triggered.connect(self.main_window.close)
        
        # 文本操作
        self.controls.get(ControlId.ACTION_EXTRACT_TEXT).triggered.connect(self._on_extract_text)
        self.controls.get(ControlId.ACTION_EXTRACT_TEXT).setShortcut(QKeySequence("Ctrl+E"))
        self.controls.get(ControlId.ACTION_EXTRACT_TEXT).setToolTip("提取选中文本 (Ctrl+E)")
        
        # 视图操作
        self.controls.get(ControlId.ACTION_SHOW_THUMB).triggered.connect(self._on_toggle_thumbnail)
        self.controls.get(ControlId.ACTION_SHOW_THUMB).setToolTip("显示/隐藏缩略栏 (F4)")
        self.controls.get(ControlId.ACTION_SHOW_THUMB).setShortcut(QKeySequence("F4"))
        
        self.controls.get(ControlId.ACTION_ZOOM_IN).triggered.connect(self._on_zoom_in)
        self.controls.get(ControlId.ACTION_ZOOM_IN).setToolTip("放大 (Ctrl++ 或 Ctrl+滚轮上滚)")
        self.controls.get(ControlId.ACTION_ZOOM_IN).setShortcut(QKeySequence("Ctrl++"))
        
        self.controls.get(ControlId.ACTION_ZOOM_OUT).triggered.connect(self._on_zoom_out)
        self.controls.get(ControlId.ACTION_ZOOM_OUT).setToolTip("缩小 (Ctrl+- 或 Ctrl+滚轮下滚)")
        self.controls.get(ControlId.ACTION_ZOOM_OUT).setShortcut(QKeySequence("Ctrl+-"))
        
        self.controls.get(ControlId.ACTION_RESET_ZOOM).triggered.connect(self._on_reset_zoom)
        self.controls.get(ControlId.ACTION_RESET_ZOOM).setToolTip("重置缩放 (Ctrl+0)")
        self.controls.get(ControlId.ACTION_RESET_ZOOM).setShortcut(QKeySequence("Ctrl+0"))
        
        # 保存模式切换
        self.controls.get(ControlId.ACTION_SAVE_MODE_AS).triggered.connect(lambda: self._set_save_mode(False))
        self.controls.get(ControlId.ACTION_SAVE_MODE_DIRECT).triggered.connect(lambda: self._set_save_mode(True))
        
        # 导航控制
        self.controls.get(ControlId.BTN_PREV_PAGE).clicked.connect(self._on_prev_page)
        self.controls.get(ControlId.BTN_NEXT_PAGE).clicked.connect(self._on_next_page)
        self.controls.get(ControlId.EDIT_PAGE).setValidator(QIntValidator(1, 9999))
        self.controls.get(ControlId.EDIT_PAGE).returnPressed.connect(self._on_page_input)
        
        # 工具栏缩放按钮
        self.controls.get(ControlId.BTN_ZOOM_IN).clicked.connect(self._on_zoom_in)
        self.controls.get(ControlId.BTN_ZOOM_OUT).clicked.connect(self._on_zoom_out)
        self.controls.get(ControlId.BTN_RESET_ZOOM).clicked.connect(self._on_reset_zoom)
        
        # 对话框操作
        self.controls.get(ControlId.BTN_CANCEL_EXPORT).clicked.connect(self._on_cancel_export)
        self.controls.get(ControlId.BTN_COPY_TEXT).clicked.connect(self._on_copy_text)
        
        # PDF文档信号
        self.pdf_doc.document_loaded.connect(self._on_document_loaded)
        self.pdf_doc.error_occurred.connect(lambda msg: QMessageBox.warning(self.main_window, "错误", msg))
        
        # 滚动事件
        self.controls.get(ControlId.SCROLL_AREA).verticalScrollBar().valueChanged.connect(self._on_scroll_changed)
    
    def eventFilter(self, obj, event):
        """事件过滤器：处理鼠标选择和滚轮缩放"""
        # 处理Ctrl+滚轮缩放
        if event.type() == QEvent.Wheel and obj == self.controls.get(ControlId.SCROLL_AREA).viewport():
            modifiers = QApplication.keyboardModifiers()
            if modifiers & Qt.ControlModifier:
                # 滚轮上滚放大，下滚缩小
                if event.angleDelta().y() > 0:
                    self._on_zoom_in(keep_position=True)
                else:
                    self._on_zoom_out(keep_position=True)
                return True  # 阻止事件进一步传播
        
        # 处理鼠标选择
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return super().eventFilter(obj, event)
        
        # 鼠标按下：开始选择
        if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton:
            if obj in (self.controls.get(ControlId.PAGES_CONTAINER), 
                      self.controls.get(ControlId.SCROLL_AREA).viewport()):
                self._selecting = True
                self._start_pos = self.controls.get(ControlId.PAGES_CONTAINER).mapFrom(
                    self.controls.get(ControlId.SCROLL_AREA).viewport(), event.pos())
                self._selected_page = self._get_page_num_from_pos(self._start_pos.y())
                return True
        
        # 鼠标移动：更新选择框
        elif event.type() == QEvent.MouseMove and self._selecting:
            if obj in (self.controls.get(ControlId.PAGES_CONTAINER), 
                      self.controls.get(ControlId.SCROLL_AREA).viewport()):
                current_pos = self.controls.get(ControlId.PAGES_CONTAINER).mapFrom(
                    self.controls.get(ControlId.SCROLL_AREA).viewport(), event.pos())
                # 计算选择区域
                x = min(self._start_pos.x(), current_pos.x())
                y = min(self._start_pos.y(), current_pos.y())
                width = abs(current_pos.x() - self._start_pos.x())
                height = abs(current_pos.y() - self._start_pos.y())
                self._current_rect = QRect(x, y, width, height)
                
                # 绘制选择框
                if not self._current_rect.isEmpty():
                    self.controls.get(ControlId.SELECTION_LAYER).setStyleSheet(
                        "background: rgba(0, 120, 215, 0.2); border: 1px solid #0078d7;")
                    self.controls.get(ControlId.SELECTION_LAYER).setGeometry(self._current_rect)
                    self.controls.get(ControlId.SELECTION_LAYER).show()
                return True
        
        # 鼠标释放：结束选择
        elif event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton:
            if self._selecting:
                self._selecting = False
                # 空选择时隐藏选择框
                if self._current_rect.isEmpty():
                    self.controls.get(ControlId.SELECTION_LAYER).hide()
                return True
        
        return super().eventFilter(obj, event)
    
    # 文件操作方法（保持不变）
    def _on_open_file(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self.main_window, "打开PDF文件", "",
            "PDF文件 (*.pdf);;所有文件 (*)"
        )
        if file_path and not self.pdf_doc.load(file_path):
            QMessageBox.warning(self.main_window, "打开失败", "无法加载选中的PDF文件")
    
    def _on_save_file(self, force_save_as=False):
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            QMessageBox.information(self.main_window, "提示", "没有打开的PDF文件")
            return
        
        if force_save_as or not self._save_mode or not self.pdf_doc.file_path:
            file_path, _ = QFileDialog.getSaveFileName(
                self.main_window, "另存为PDF文件", 
                self.pdf_doc.file_path if self.pdf_doc.file_path else "",
                "PDF文件 (*.pdf);;所有文件 (*)"
            )
            if not file_path:
                return
        else:
            file_path = self.pdf_doc.file_path
        
        if self.pdf_doc.save(file_path):
            self.main_window.statusBar().showMessage(f"已保存到: {file_path}")
        else:
            QMessageBox.warning(self.main_window, "保存失败", "无法保存PDF文件")
    
    def _on_export_word(self):
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            QMessageBox.information(self.main_window, "提示", "没有打开的PDF文件")
            return
        
        all_text = []
        for page_num in range(self.pdf_doc.get_page_count()):
            page = self.pdf_doc.get_page(page_num)
            if page:
                all_text.append(f"=== 第 {page_num + 1} 页 ===\n")
                all_text.append(page.get_text())
        
        dialog = self.controls.get(ControlId.EXPORT_DIALOG)
        text_edit = self.controls.get(ControlId.EXPORT_TEXT_EDIT)
        text_edit.setText("\n".join(all_text))
        dialog.exec_()
    
    # 视图控制方法（保持不变）
    def _on_zoom_in(self, keep_position=True):
        """放大视图（修复：强制保持当前页）"""
        new_zoom = self._zoom + 0.1
        if 0.1 <= new_zoom <= 5.0:
            self._zoom = new_zoom
            self.controls.get(ControlId.LBL_ZOOM).setText(f"{int(self._zoom * 100)}%")
            # 强制保持当前页，即使计算出错也手动锁定
            self._update_display(keep_position=keep_position, force_current_page=True)
    
    def _on_zoom_out(self, keep_position=True):
        """缩小视图（修复：强制保持当前页）"""
        new_zoom = self._zoom - 0.1
        if 0.1 <= new_zoom <= 5.0:
            self._zoom = new_zoom
            self.controls.get(ControlId.LBL_ZOOM).setText(f"{int(self._zoom * 100)}%")
            # 强制保持当前页
            self._update_display(keep_position=keep_position, force_current_page=True)
    
    def _on_reset_zoom(self):
        """重置缩放（修复：强制保持当前页）"""
        if abs(self._zoom - 1.0) > 0.01:
            self._zoom = 1.0
            self.controls.get(ControlId.LBL_ZOOM).setText("100%")
            # 强制保持当前页
            self._update_display(keep_position=True, force_current_page=True)

    
    def _on_toggle_thumbnail(self):
        is_visible = self.thumbnail_sidebar.isVisible()
        self.thumbnail_sidebar.setVisible(not is_visible)
        self.controls.get(ControlId.ACTION_SHOW_THUMB).setChecked(not is_visible)
        
        splitter = self.controls.get(ControlId.SPLITTER)
        if not is_visible:
            splitter.setSizes([150, 1050])
        else:
            splitter.setSizes([0, 1200])
    
    # 页面导航方法（保持不变）
    def _on_prev_page(self):
        if self._total_pages > 0 and self._current_page > 0:
            self._current_page -= 1
            self._update_page_display()
            self._scroll_to_page(self._current_page)
    
    def _on_next_page(self):
        if self._total_pages > 0 and self._current_page < self._total_pages - 1:
            self._current_page += 1
            self._update_page_display()
            self._scroll_to_page(self._current_page)
    
    def _on_page_input(self):
        try:
            page_num = int(self.controls.get(ControlId.EDIT_PAGE).text()) - 1
            if 0 <= page_num < self._total_pages:
                self._current_page = page_num
                self._update_page_display()
                self._scroll_to_page(self._current_page)
            else:
                QMessageBox.warning(self.main_window, "无效页码", 
                                   f"请输入1到{self._total_pages}之间的页码")
        except ValueError:
            QMessageBox.warning(self.main_window, "输入错误", "请输入有效的页码")
    
    def _scroll_to_page(self, page_num):
        if not hasattr(self, '_page_positions'):
            return
            
        if page_num in self._page_positions:
            scroll_bar = self.controls.get(ControlId.SCROLL_AREA).verticalScrollBar()
            scroll_bar.setValue(self._page_positions[page_num] - 20)
    
    def _get_page_num_from_pos(self, y_pos):
        page_nums = []
        for key in self._page_positions.keys():
            if isinstance(key, int):
                page_nums.append(key)
        
        for page_num in sorted(page_nums):
            page_start = self._page_positions[page_num]
            page_end = page_start + self._page_positions.get(f"{page_num}_height", 0)
            if page_start <= y_pos <= page_end:
                return page_num
        return -1
    
    # --- 核心修复：删除页面后跳转逻辑 ---
    def _on_delete_page(self, page_num):
        """删除指定页面并优化导航（修复最后一页跳转）"""
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return
            
        # 统一在这里弹确认（仅一次）
        reply = QMessageBox.question(
            self.main_window, 
            "确认删除", 
            f"确定要删除第 {page_num + 1} 页吗？",
            QMessageBox.Yes | QMessageBox.No, 
            QMessageBox.No
        )
        
        if reply != QMessageBox.Yes:
            return
        #删除前保存缩略栏滚动位置
        scroll_pos = self.thumbnail_sidebar.save_scroll_position()
        # 记录删除前的状态（关键：用old_total判断是否是最后一页）
        old_total = self._total_pages
        current_page = self._current_page
        
        # 执行删除
        if self.pdf_doc.delete_page(page_num):
            new_total = self.pdf_doc.get_page_count()
            
            # --- 修复：精准计算新页码 ---
            if new_total == 0:
                new_page = 0  # 文档空了，页码设为0
            elif page_num == current_page:
                # 删除的是当前查看的页
                if page_num == old_total - 1:
                    # 情况1：删除的是最后一页 → 跳上一页（如11页删完跳10页）
                    new_page = page_num - 1
                else:
                    # 情况2：删除中间页 → 跳原位置（原下一页）
                    new_page = page_num
            elif page_num < current_page:
                # 情况3：删除当前页之前的页 → 页码减1
                new_page = current_page - 1
            else:
                # 情况4：删除当前页之后的页 → 页码不变
                new_page = current_page
            
            # 强制边界检查（防止new_page为负或超出范围）
            new_page = max(0, min(new_page, new_total - 1))
            
            # 更新状态（先更页码，再刷新显示）
            self._current_page = new_page
            self._total_pages = new_total
            
            # 先更新缩略图，再恢复滚动位置
            self._update_thumbnails()
            # 恢复滚动位置（延迟10ms确保UI已刷新）
            QApplication.processEvents()  # 强制刷新UI
            self.thumbnail_sidebar.restore_scroll_position(scroll_pos)
            
            # 确保当前选中的缩略图可见（防止被滚动位置遮挡）
            self.thumbnail_sidebar.scroll_area.ensureWidgetVisible(
                self.thumbnail_sidebar._thumb_widgets[new_page]
            )

            # 同步更新页码输入框（防止显示旧值）
            self.controls.get(ControlId.EDIT_PAGE).setText(str(new_page + 1))
            self.controls.get(ControlId.LBL_PAGE_COUNT).setText(f"/ {new_total}")
            
            # 刷新页面和缩略图（keep_position=True避免跳开头）
            self._update_display(keep_position=True)
            # 同步缩略图选中状态
            self.thumbnail_sidebar.set_selected(new_page)
            
            # 状态栏提示
            self.main_window.statusBar().showMessage(
                f"已删除第 {page_num + 1} 页，当前显示第 {new_page + 1} 页，共 {new_total} 页"
            )
        else:
            QMessageBox.warning(
                self.main_window, 
                "删除失败", 
                f"无法删除第 {page_num + 1} 页"
            )
    
    # 文档显示与更新（保持不变）
    def _on_document_loaded(self):
        self._total_pages = self.pdf_doc.get_page_count()
        self._current_page = 0
        self._page_cache.clear()
        self._page_positions.clear()
        
        self.main_window.statusBar().showMessage(
            f"已加载: {self.pdf_doc.file_path} ({self._total_pages} 页)")
        
        self.controls.get(ControlId.EDIT_PAGE).setText("1")
        self.controls.get(ControlId.LBL_PAGE_COUNT).setText(f"/ {self._total_pages}")
        
        self._update_display()
    
    def _update_display(self, keep_position=False, force_current_page=False):
        """更新页面显示（核心修复）"""
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return
        
        # 关键：保存当前页码（无论如何不丢失）
        saved_current_page = self._current_page
        
        # 保存滚动位置信息（用于恢复视图）
        scroll_bar = self.controls.get(ControlId.SCROLL_AREA).verticalScrollBar()
        current_scroll_pos = scroll_bar.value()
        viewport_height = self.controls.get(ControlId.SCROLL_AREA).viewport().height()
        view_center_y = current_scroll_pos + viewport_height / 2
        
        # 清除旧页面
        self._clear_layout()
        self._page_cache.clear()
        self._page_positions.clear()
        
        current_y = 20
        total_pages = self.pdf_doc.get_page_count()
        
        # 渲染所有页面
        for page_num in range(total_pages):
            page_label = self._render_page(page_num)
            if page_label:
                self._page_positions[page_num] = current_y
                self._page_positions[f"{page_num}_height"] = page_label.pixmap().height()
                self.controls.get(ControlId.PAGES_LAYOUT).addWidget(page_label)
                current_y += page_label.pixmap().height() + 20
        
        # 更新缩略图
        self._update_thumbnails()
        
        # 设置容器尺寸
        total_height = current_y + 20
        self.controls.get(ControlId.PAGES_CONTAINER).setMinimumHeight(total_height)
        self.controls.get(ControlId.PAGES_CONTAINER).setMaximumHeight(total_height)
        self.controls.get(ControlId.PAGES_CONTAINER).setMinimumWidth(
            self.controls.get(ControlId.SCROLL_AREA).width() - 40)
        
        # 调整覆盖层大小
        self.controls.get(ControlId.OVERLAY_CONTAINER).setGeometry(
            0, 0, self.controls.get(ControlId.PAGES_CONTAINER).width(), total_height)
        self.controls.get(ControlId.SELECTION_LAYER).setGeometry(
            0, 0, self.controls.get(ControlId.PAGES_CONTAINER).width(), total_height)
        
        # 恢复页码和位置（核心修复逻辑）
        # 强制恢复到缩放前的页码，防止被意外重置
        if force_current_page:
            self._current_page = saved_current_page
            self._update_page_display()  # 同步更新页码输入框和缩略图选中状态
        
        # 恢复视图位置
        if keep_position and total_pages > 0:
            if force_current_page:
                # 缩放时强制滚动到保存的页码
                self._scroll_to_page(saved_current_page)
            else:
                # 其他情况按原逻辑恢复
                if saved_current_page in self._page_positions:
                    page_start = self._page_positions[saved_current_page]
                    page_height = self._page_positions[f"{saved_current_page}_height"]
                    new_center_y = page_start + page_height / 2
                    new_scroll_pos = new_center_y - viewport_height / 2
                    scroll_bar.setValue(int(new_scroll_pos))
                else:
                    self._scroll_to_page(saved_current_page)
    
    def _render_page(self, page_num):
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return None
        
        if page_num in self._page_cache:
            cached_label = self._page_cache[page_num]
            if cached_label and cached_label.parent():
                return cached_label
        
        try:
            page = self.pdf_doc.get_page(page_num)
            pix = page.get_pixmap(matrix=fitz.Matrix(self._zoom, self._zoom))
            
            if pix.n == 4:
                q_image = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_RGBA8888)
                q_image = q_image.convertToFormat(QImage.Format_RGB888)
            elif pix.n == 3:
                q_image = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_RGB888)
            else:
                q_image = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_Grayscale8)
            
            page_label = QLabel()
            page_label.setPixmap(QPixmap.fromImage(q_image))
            page_label.setAlignment(Qt.AlignCenter)
            self._page_cache[page_num] = page_label
            return page_label
        
        except Exception as e:
            QMessageBox.warning(self.main_window, "渲染失败", f"页面 {page_num + 1}：{str(e)}")
            return None
    
    def _update_thumbnails(self):
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return
        
        self.thumbnail_sidebar.clear_thumbnails()
        
        total_pages = self.pdf_doc.get_page_count()
        for page_num in range(total_pages):
            try:
                page = self.pdf_doc.get_page(page_num)
                pix = page.get_pixmap(matrix=fitz.Matrix(0.2, 0.2))
                
                if pix.n == 4:
                    q_image = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_RGBA8888)
                    q_image = q_image.convertToFormat(QImage.Format_RGB888)
                else:
                    q_image = QImage(pix.samples, pix.width, pix.height, pix.stride, QImage.Format_RGB888)
                
                pixmap = QPixmap.fromImage(q_image)
                self.thumbnail_sidebar.add_thumbnail(
                    pixmap, 
                    page_num, 
                    self._on_thumbnail_click
                )
                
            except Exception as e:
                QMessageBox.warning(self.main_window, "缩略图生成失败", f"页面 {page_num + 1}：{str(e)}")
        
        if total_pages > 0:
            self.thumbnail_sidebar.set_selected(0)
    
    def _on_thumbnail_click(self, page_num):
        if 0 <= page_num < self._total_pages:
            self._current_page = page_num
            self._update_page_display()
            self._scroll_to_page(self._current_page)
            self.thumbnail_sidebar.set_selected(page_num)
    
    def _update_page_display(self):
        self.controls.get(ControlId.EDIT_PAGE).setText(str(self._current_page + 1))
        self.thumbnail_sidebar.set_selected(self._current_page)
    
    def _on_scroll_changed(self, value):
        if not self._page_positions or self._total_pages == 0:
            return
            
        viewport_height = self.controls.get(ControlId.SCROLL_AREA).viewport().height()
        mid_scroll = value + viewport_height / 2
        
        page_nums = []
        for key in self._page_positions.keys():
            if isinstance(key, int):
                page_nums.append(key)
        
        for page_num in sorted(page_nums):
            page_start = self._page_positions.get(page_num, 0)
            page_height = self._page_positions.get(f"{page_num}_height", 0)
            
            if page_start <= mid_scroll <= page_start + page_height:
                if page_num != self._current_page:
                    self._current_page = page_num
                    self._update_page_display()
                break
    
    # 文本提取相关（保持不变）
    def _on_extract_text(self):
        if not self.pdf_doc or not self.pdf_doc.is_loaded:
            return
        
        if self._selected_page == -1 or self._current_rect.isEmpty():
            QMessageBox.information(self.main_window, "提示", "请先在页面上选择文本区域")
            return
        
        try:
            page = self.pdf_doc.get_page(self._selected_page)
            if not page:
                return
            
            page_height = self._page_positions.get(f"{self._selected_page}_height", 0)
            if page_height == 0:
                return
                
            scale_x = page.rect.width / self.controls.get(ControlId.PAGES_CONTAINER).width()
            scale_y = page.rect.height / page_height
            
            pdf_rect = fitz.Rect(
                self._current_rect.x() * scale_x,
                (page_height - self._current_rect.y() - self._current_rect.height()) * scale_y,
                (self._current_rect.x() + self._current_rect.width()) * scale_x,
                (page_height - self._current_rect.y()) * scale_y
            )
            
            text = page.get_textbox(pdf_rect)
            
            if text:
                self.controls.get(ControlId.EXPORT_TEXT_EDIT).setText(text)
                self.controls.get(ControlId.EXPORT_DIALOG).setWindowTitle(f"提取的文本 - 第 {self._selected_page + 1} 页")
                self.controls.get(ControlId.EXPORT_DIALOG).exec_()
            else:
                QMessageBox.information(self.main_window, "提示", "选中区域没有文本")
                
        except Exception as e:
            QMessageBox.warning(self.main_window, "提取失败", f"文本提取错误: {str(e)}")
    
    def _on_copy_text(self):
        text = self.controls.get(ControlId.EXPORT_TEXT_EDIT).toPlainText()
        if text:
            clipboard = QApplication.clipboard()
            clipboard.setText(text)
            self.main_window.statusBar().showMessage("文本已复制到剪贴板")
    
    def _on_cancel_export(self):
        self.controls.get(ControlId.EXPORT_DIALOG).close()
        self.controls.get(ControlId.SELECTION_LAYER).hide()
        self._current_rect = QRect()
    
    # 辅助方法（保持不变）
    def _clear_layout(self):
        layout = self.controls.get(ControlId.PAGES_LAYOUT)
        while layout.count():
            item = layout.takeAt(0)
            widget = item.widget()
            if widget:
                widget.deleteLater()
    
    def _set_save_mode(self, direct_save):
        self._save_mode = direct_save
